package com.dzsw.zk.seq;

import com.dzsw.zk.util.NumberUtil;
import com.google.common.base.Strings;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class SeqTask {

    private InterProcessMutex lock;

    private CuratorFramework client;

    public SeqTask(CuratorFramework client) {
        this.client = client;
        this.lock = new InterProcessMutex(client, Const.LOCK_ZNODE);
    }

    public boolean existsAndCreate(String path) {
        try {
            Stat stat = this.client.checkExists().forPath(path);
            if (stat == null) {
                this.client.create()
                        .creatingParentsIfNeeded()
                        .withMode(CreateMode.PERSISTENT)
                        .forPath(path);
            }
            return true;
        } catch (Exception ex) {
            return false;
        }
    }

    public String getSequence(String path) throws Exception {
//        InterProcessMutex lock = new InterProcessMutex(client, path);
        try {
            boolean retry = true;
            byte[] newData = null;
            do {
                if (lock.acquire(1000, TimeUnit.MILLISECONDS)) {
                    byte[] oldData = client.getData().forPath(path);
                    String strTmp = new String(oldData);
                    if (Strings.isNullOrEmpty(strTmp)) {
                        strTmp = Const.INIT_VAL;
                    }
                    long tmp = Integer.parseInt(strTmp);
                    tmp = tmp + 1;
                    tmp = NumberUtil.giveUpNum(tmp, 4);
                    strTmp = String.valueOf(tmp);
                    newData = strTmp.getBytes();
                    client.setData().forPath(path, newData);
                    retry = false;
                }
            } while (retry);
            return new String(newData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (lock.isAcquiredInThisProcess()) {
                    lock.release();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
//        test1();
//        test2();
        test3();
    }

    public static void test1() throws Exception {
        final String path = "/fjec/market/102";
        CuratorFramework client = new ZookeeperClient().getZookeeperInstance().build();
        client.start();
        SeqTask seqTask = new SeqTask(client);
        seqTask.existsAndCreate(path);
        System.out.println(seqTask.getSequence(path));
    }

    public static void test2() throws Exception {
        ExecutorService executors = Executors.newFixedThreadPool(20);
        final String path = "/fjec/market/102";
        for (int i = 0; i < 3000; i++) {
            executors.execute(()-> {
                CuratorFramework client = new ZookeeperClient().getZookeeperInstance().build();
                try {
                    client.start();
                    SeqTask seqTask = new SeqTask(client);
                    seqTask.existsAndCreate(path);
                    System.out.println(seqTask.getSequence(path));
                } catch (Exception ex) {
                    ex.printStackTrace();
                } finally {
                    client.close();
                }
            });
        }
    }

    public static void test3() throws Exception {
        CuratorFramework client = new ZookeeperClient().getZookeeperInstance().build();
        client.start();
        final String path = "/fjec/market/102";
        for (int i = 0; i < 5; i++) {
            try {
                SeqTask seqTask = new SeqTask(client);
                seqTask.existsAndCreate(path);
                System.out.println(seqTask.getSequence(path));
//                Thread.sleep(1000);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}
